﻿using UnityEngine;
using WOA.Model;
using Rpc;

namespace Complete
{
    public class TankMovement : MonoBehaviour
    {
        public int m_PlayerNumber = 1;              // Used to identify which tank belongs to which player.  This is set by this tank's manager.
        public float m_Speed = 12f;                 // How fast the tank moves forward and back.
        public float m_TurnSpeed = 180f;            // How fast the tank turns in degrees per second.
        public AudioSource m_MovementAudio;         // Reference to the audio source used to play engine sounds. NB: different to the shooting audio source.
        public AudioClip m_EngineIdling;            // Audio to play when the tank isn't moving.
        public AudioClip m_EngineDriving;           // Audio to play when the tank is moving.
        public float m_PitchRange = 0.2f;           // The amount by which the pitch of the engine noises can vary.

        private string m_MovementAxisName;          // The name of the input axis for moving forward and back.
        private string m_TurnAxisName;              // The name of the input axis for turning.
        private Rigidbody m_Rigidbody;              // Reference used to move the tank.
        private float m_MovementInputValue;         // The current value of the movement input.
        private float m_TurnInputValue;             // The current value of the turn input.
        private float m_OriginalPitch;              // The pitch of the audio source at the start of the scene.

        private bool m_SyncPositiion = false;       // Initial position synchronization
        private bool m_OnRotating = false;          // Control sync rotate
        private Quaternion m_TargetRotation;

        private bool m_OnMoving = false;
        private Vector3 m_TargetPosition;
        private Vector3 velocity;
        private float smoothTime = 0.3f;

        private int m_ControlTime = 0;              // Control time to update

        private void Awake()
        {
            m_Rigidbody = GetComponent<Rigidbody>();
        }


        private void OnEnable()
        {
            // When the tank is turned on, make sure it's not kinematic.
            m_Rigidbody.isKinematic = false;

            // Also reset the input values.
            m_MovementInputValue = 0f;
            m_TurnInputValue = 0f;
        }


        private void OnDisable()
        {
            // When the tank is turned off, set it to kinematic so it stops moving.
            m_Rigidbody.isKinematic = true;
        }


        private void Start()
        {
            // The axes names are based on player number.
            m_MovementAxisName = "Vertical1";
            m_TurnAxisName = "Horizontal1";

            // Store the original pitch of the audio source.
            m_OriginalPitch = m_MovementAudio.pitch;

            //Initial position synchronization
            if (IsControlledByMe() && !m_SyncPositiion)
            {
                Controller.RequestMoveTo(m_Rigidbody.position);
                m_SyncPositiion = true;
            }
        }


        private void Update()
        {
            // Store the value of both input axes.
            m_MovementInputValue = Input.GetAxis(m_MovementAxisName);
            m_TurnInputValue = Input.GetAxis(m_TurnAxisName);

            EngineAudio();

            /*
            if (m_Rigidbody.rotation == m_TargetRotation)
                m_OnRotating = false;

            if(m_OnRotating)
            {
                m_Rigidbody.rotation = Quaternion.Slerp(m_Rigidbody.rotation, m_TargetRotation, Time.deltaTime * 3);
            }
            */
            smoothTime = Time.deltaTime;
            if (m_Rigidbody.position == m_TargetPosition)
                m_OnMoving = false;
            if(m_OnMoving)
            {
                m_Rigidbody.position = new Vector3(Mathf.SmoothDamp(m_Rigidbody.position.x, m_TargetPosition.x, ref velocity.x, smoothTime),
                    Mathf.SmoothDamp(transform.position.y, m_TargetPosition.y, ref velocity.y, smoothTime),
                    Mathf.SmoothDamp(transform.position.z, m_TargetPosition.z, ref velocity.z, smoothTime));
            }
            
        }

        private void EngineAudio()
        {
            // If there is no input (the tank is stationary)...
            if (Mathf.Abs(m_MovementInputValue) < 0.1f && Mathf.Abs(m_TurnInputValue) < 0.1f)
            {
                // ... and if the audio source is currently playing the driving clip...
                if (m_MovementAudio.clip == m_EngineDriving)
                {
                    // ... change the clip to idling and play it.
                    m_MovementAudio.clip = m_EngineIdling;
                    m_MovementAudio.pitch = Random.Range(m_OriginalPitch - m_PitchRange, m_OriginalPitch + m_PitchRange);
                    m_MovementAudio.Play();
                }
            }
            else
            {
                // Otherwise if the tank is moving and if the idling clip is currently playing...
                if (m_MovementAudio.clip == m_EngineIdling)
                {
                    // ... change the clip to driving and play.
                    m_MovementAudio.clip = m_EngineDriving;
                    m_MovementAudio.pitch = Random.Range(m_OriginalPitch - m_PitchRange, m_OriginalPitch + m_PitchRange);
                    m_MovementAudio.Play();
                }
            }
        }


        private void FixedUpdate()
        {
            if (!IsControlledByMe())
                return;

            //每隔1s强制同步一次方位
            //降低数据传输量
            m_ControlTime++;
            if(m_ControlTime % 50 == 0)
            {
                Rpc.Controller.RequestMoveTo(m_Rigidbody.position);
                Rpc.Controller.RequestRotateTo(m_Rigidbody.rotation.eulerAngles.y);
            }
            if (m_ControlTime >= 5000)
                m_ControlTime = 1;

            // Adjust the rigidbodies position and orientation in FixedUpdate.
            Move();
            Turn();
        }


        private void Move()
        {
            // Create a vector in the direction the tank is facing with a magnitude based on the input, speed and the time between frames.
            Vector3 movement = transform.forward * m_MovementInputValue * m_Speed * Time.deltaTime;

            // Apply this movement to the rigidbody's position.
            var toPosition = m_Rigidbody.position + movement;

            if (Mathf.Abs(m_MovementInputValue) > 0.1f)
            {
                Rpc.Controller.RequestMoveTo(toPosition);
            }

            m_Rigidbody.MovePosition(toPosition);
        }

        // Controlled by remote.
        public void MoveTo(Vector3 position)
        {
            //m_Rigidbody.MovePosition(position);

            m_OnMoving = true;
            m_TargetPosition = position;
        }

        private void Turn ()
        {
            // Determine the number of degrees to be turned based on the input, speed and time between frames.
            float turn = m_TurnInputValue * m_TurnSpeed * Time.deltaTime;

            // Make this into a rotation in the y axis.
            Quaternion turnRotation = Quaternion.Euler (0f, turn, 0f);

            // Apply this rotation to the rigidbody's rotation.
            m_Rigidbody.MoveRotation (m_Rigidbody.rotation * turnRotation);

            if (Mathf.Abs(m_TurnInputValue) > 0.1f)
            {
                float r = m_Rigidbody.rotation.eulerAngles.y;
                Rpc.Controller.RequestRotateTo(r);
            }
        }
        public void RotateTo(float turn)
        {
            //m_OnRotating = true;
           // float turn = r * m_TurnSpeed * Time.deltaTime;
            Quaternion turnRotation = Quaternion.Euler(0f, turn, 0f);
            //m_TargetRotation = m_Rigidbody.rotation * turnRotation;
            m_Rigidbody.MoveRotation(/*m_Rigidbody.rotation * */turnRotation);
        }

        private bool IsControlledByMe()
        {
            return m_PlayerNumber == Tanks.TanksPushService.m_MyPlayerNumber;
        }
    }
}